#include <iostream>
#include <string>
#include "sdl.h"
#include "Shapes.h"
#include "Scene.h"
#include "RayTracer.h"
#include "Color.h"
#include "SDLRenderer.h"
#include "Material.h"
#include "Matrix.h"
#include "Transform.h"
#include "Point.h"
#include "Orthographic.h"

using std::cout;
using std::cin;
using std::endl;
using std::string;

using GeometryPrimitives::Sphere;
//using GeometryPrimitives::Plane;
using GeometryPrimitives::PointLight;
using MathGraphics::Vector;
using GraphicsColor::RGB;
using RayTracerInterface::RayTracer; 
using Renderer::SDLRenderer;
using LightingMaterial::Material;
using MathGraphics::Matrix;
using MathGraphics::Transform;
using MathGraphics::orthographic;
using MathGraphics::translate;
using MathGraphics::scale;
using MathGraphics::Point;
using MathGraphics::Ray;
using CameraInterface::OrthoCamera;

int main(int argc, char* argv[])
{	
	Scene scene(1680, 1050, 32);
	
	//sphere
	Material m0(0.0f, 0.5f);
	Vector v0(1.0, 0.0, 300.0);
	RGB c0(255, 0, 0);
	Sphere s1(translate(v0), 0.5, &c0, m0);
	scene.addObject(&s1); 
/*
	//back wall
	Material m1(0.0, 0.0);
	Vector v1(0.0, 0.0, -1.0);
	Vector pos(0.0, 0.0, 4000.0);
	RGB c1(255, 255, 255);
	Plane p1(&v1, &pos, &c1, m1);
	scene.addObject(&p1);
*/

	//sphere
	Material m2(0.0f, 0.4f);
	Vector v2(0.0, 0.0, 440.0);
	RGB c2(0, 255, 0);
	Sphere s2(translate(v2), 0.5, &c2, m2);
	scene.addObject(&s2);

	//sphere
	Material m9(0.0, 0.0);
	Vector v9(-1.0, 0.0, 2400.0);
	RGB c9(0, 0, 255);
	Sphere s3(translate(v9), 0.5, &c9, m9);
	scene.addObject(&s3);
/*
	//sphere
	Material m10(0.0, 0.0);
	Vector v10(700.0,770.0, 2400.0);
	RGB c10(139, 0, 204);
	Sphere s4(&v10, 140, &c10, m10, translate(v10));
	scene.addObject(&s4);

	//sphere
	Material m11(0.0, 0.0);
	Vector v11(-280.0,700.0, 2500.0);
	RGB c11(0, 0, 255);
	Sphere s5(&v11, 290, &c11, m11, translate(v11));
	scene.addObject(&s5);*/

/*
	//floor
	Material m3(0.0, 0.5);
	Vector v3(0.0, -1.0, 0);
	Vector pos2(0.0, 1000.0, 0.0);
	RGB c3(76, 76, 76);
	Plane p2(&v3, &pos2, &c3, m3);
	scene.addObject(&p2); */

/*
	//right wall
	Material m4(0.0, 0.0);
	Vector v4(-1, 0.0, 0);
	Vector pos3(1700.0, 0.0, 0.0);
	RGB c4(40, 92, 19);
	Plane p3(&v4, &pos3, &c4, m4);
	scene.addObject(&p3);


	//left wall
	Material m5(0.0, 0.0);
	Vector v5(1, 0.0, 0);
	Vector pos4(-100.0, 0.0, 0.0);
	RGB c5(255, 0, 0);
	Plane p4(&v5, &pos4, &c5, m5);
	scene.addObject(&p4);


	//ceiling
	Material m6(0.0, 0.0);
	Vector v6(0.0, 1.0, 0.0);
	Vector pos5(0.0, -200.0, 0.0);
	RGB c6(255, 255, 255);
	Plane p5(&v6, &pos5, &c6, m6);
	scene.addObject(&p5);
*/

	Material m8(0.0f, 1.0f);
	Vector v8(2.0, -3.0, 275.0);
	PointLight pl(translate(v8), m8);
	scene.addLight(&pl);

	SDLRenderer render(1680, 1050, 32);

	RayTracer rt(&scene, &render);

	int t1 = SDL_GetTicks();
	rt.rayTrace();
	int t2 = SDL_GetTicks();

	render.saveScreenShot();

	cout<<"Time: "<<(t2 - t1) / 1000.0f<<endl;

	Matrix mat1;
	Matrix mat2;
	Transform worldToCamera = lookAt(Point(0.0, 0.0, 0.0), Point(0.0, 0.0, 1.0), Vector(0.0, 1.0, 0.0));
	//mat3 = MathGraphics::rotateX(3.14159265) * mat3;
	Point v000 = worldToCamera(Point(840.0, 525.0, 0.0));

	cout<<v000.x<<endl;
	cout<<v000.y<<endl;
	cout<<v000.z<<endl;
	cout<<endl<<endl<<endl;


	for (int i = 0; i < 4; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			cout<<worldToCamera.mat.d[i][j]<<"  ";
		}
		cout<<endl;
	}

	cout<<endl<<endl;

	double screen[4] = {0};

	double ratio = 1680.0 / 1050.0;
	screen[0] = - ratio;
	screen[1] = ratio;
	screen[2] = 1.0;
	screen[3] = -1.0;

	cout<<"screenRatio: "<<screen[1]<<endl;
	cout<<"Point 840, 525 Raster to Screen: "<<endl; 

	Transform screenToRaster =  MathGraphics::scale(1680, 1050, 1) * 
		                        MathGraphics::scale(1.0 / (screen[1] - screen[0]), 1.0 / (screen[2] - screen[3]), 1) * 
		                        MathGraphics::translate(Vector(-screen[0], -screen[3], 0));

	Transform rasterToScreen(screenToRaster.inv, screenToRaster.mat);

	Point screenPoint = screenToRaster(Point(1.6, -1, 1));
	//cout<<screenPoint.x<<endl;
	//cout<<screenPoint.y<<endl;
	//cout<<screenPoint.z<<endl;

	OrthoCamera camera = OrthoCamera(1680, 1050, 1.0, 1000.0, worldToCamera);
	Ray test = camera.spawnRay(840, 525);
	/*cout<<test.o.x<<endl;
	cout<<test.o.y<<endl;
	cout<<test.o.z<<endl;
	cout<<test.v.x<<endl;
	cout<<test.v.y<<endl;
	cout<<test.v.z<<endl;
	*/
	/*
	Transform proj(orthographic(100.0, 200).inv);
	Point r = proj(Point(0.0, 0.0, 0.0));
	cout<<r.z;
*/
	
	while (1)
	{
		render.render();

		// Poll for events, and handle the ones we care about.
		SDL_Event event;
		while (SDL_PollEvent(&event)) 
		{
		  switch (event.type) 
		  {
		  case SDL_KEYDOWN:
			break;
		  case SDL_KEYUP:
			// If escape is pressed, return (and thus, quit)
			if (event.key.keysym.sym == SDLK_ESCAPE)
			  return 0;
			break;
		  case SDL_QUIT:
			return(0);
		  }
		}
		SDL_Delay(1);
	}

	cin.get();
	return 0;
}
